package wxdb.index.btree;

import java.io.Serializable;

import wxdb.index.Index;
import wxdb.query.Constant;
import wxdb.query.IntConstant;
import wxdb.query.StringConstant;
import wxdb.record.RID;
import wxdb.record.Schema;
import wxdb.record.TableInfo;
import wxdb.tx.Transaction;
import wxdb.index.btree.BTreePageFormatter;
import static java.sql.Types.*;

public class BTreeIndex implements Index, Serializable{
	
	private TableInfo dirTi, leafTi;
	private int rootPid;
	private BTreeLeaf leaf;
	
	public BTreeIndex(){
		
	}
	public BTreeIndex(int dbid, Schema sch) {
		//initiate leaf
		leafTi = new TableInfo(dbid, sch);
		int lpid = Transaction.append(dbid, 
				new BTreePageFormatter(leafTi, -1));
		leafTi.addPage(-1, lpid);
		
		//initiate dir
		Schema dirSch = new Schema();
		dirSch.add("dataval", sch);
		dirSch.add("pid", sch);
		dirTi = new TableInfo(dbid, dirSch);
		int rpid = Transaction.append(dbid, 
				new BTreePageFormatter(dirTi, 0));
		dirTi.addPage(-1, rpid);		
		BTreePage page = new BTreePage(rpid, dirTi);
		if(page.getTotalSlotNum() == 0){
			//insert inital minimun entry
			if(sch.getType("dataval") == INTEGER)
				page.insertDir(0, new IntConstant(Integer.MIN_VALUE), lpid);
			else if(sch.getType("dataval") == VARCHAR)
				page.insertDir(0, new StringConstant(""), lpid);
		}
		rootPid = rpid;
	}
	
	
	public boolean beforeFirst(Constant searchKey) {
		BTreeDir root = new BTreeDir(this.rootPid, this.dirTi); 
		int pid = root.search(searchKey);
		if(pid < 0)
			return false;
		else{
			this.leaf = new BTreeLeaf(pid, searchKey, this.leafTi);
			return true;
		}
	}
	
	public void moveToHead(){
		this.leaf = new BTreeLeaf(leafTi.getTruePid(0), null, this.leafTi);
	}
	
	public boolean next() {
		return leaf.next();
	}
	
	public boolean nextSlot(){
		if(!leaf.nextSlot()){
			int curLeafPid = leaf.getLeafPid();
			int nextPid = leafTi.getNextPid(curLeafPid);
			if(nextPid == -1)
				return false;
			leaf = new BTreeLeaf(nextPid, null, this.leafTi);
			return true;
		}
		return true;
			
	}
	
	public boolean preSlot(){
		if(!leaf.preSlot()){
			int curLeafPid = leaf.getLeafPid();
			int prePid = leafTi.getPrePid(curLeafPid);
			if(prePid == -1)
				return false;
			leaf = new BTreeLeaf(prePid, null, this.leafTi);
			return true;
		}
		return true;
	}
	
	public boolean insert(Constant searchKey, RID rid) {
		if(!beforeFirst(searchKey))
			return false;
		DirEntry de1 = leaf.insert(rid);
		if(de1 == null)
			return true;
		BTreeDir root = new BTreeDir(this.rootPid, this.dirTi);
		DirEntry de2 = root.insert(de1);
		if(de2 != null)
			root.makeNewRoot(de2);
		return true;
		
	}
	
	public boolean delete(Constant searchKey, RID rid) {
		if(!beforeFirst(searchKey))
			return false;
		leaf.delete(rid);
		return true;
	}
	
	public RID getRID() {
		return leaf.getDataRid();
	}
	
	
}
